package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.*;
import com.myk.game.gobangchess.constants.BoardStyleData;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.rooms.absrooms.AbsSameTimeRoom;
import com.myk.game.gobangchess.constants.Msger;
import com.myk.game.gobangchess.signs.BadgeSign;
import com.myk.game.gobangchess.signs.GroundSign;
import com.myk.game.gobangchess.signs.LineSign;
import com.myk.game.gobangchess.utils.GridsUtils;
import com.myk.game.gobangchess.utils.SignsUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 逆界天弈五子棋 （夏日设计的）
 */
public class AntiSameTimeGoBangRoom extends AbsSameTimeRoom {

    private boolean isModifying = false;
    private int[] needUpdated; //修改落子后原位置要变成的值（长度为3的数组，分别是：行，列，值）

    public AntiSameTimeGoBangRoom(String roomName) {
        super(roomName, "\t\t\t\t夏日和日出定制的同步五子棋，落在同一位置随机一人重下，若同时成五则互挡，不可调和就变墙。","逆界天弈五子棋", BoardStyleData.getGoBangStyle(15,15), false,true);
    }

    @Override
    public String getRuleText() {
        return " * 落子在不同位置时：双方都成5 → 互换 仍然都成5 -> 墙\n" +
                " * 落子在同一位置时：\n" +
                " * 1、双方都成5 → 墙\n" +
                " * 2、A有5，B没有 → A改\n" +
                " * 3、其他情况 → 随机一方改";
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        isModifying = false;
        needUpdated = null;
    }

    //通知黑方行棋
    protected void noticeBlackModify() {
        cur = 1;
        if (player_black != null) {
            player_black.sendMessage(Msger.youCanMove, "Ok");
        }
        if (player_white != null) {
            player_white.sendMessage(Msger.youNotMove, "Ok");
        }
        noticeAllRefreshGameInfo();
        noticeAllCountdown(getCountdownSec(), -1);
    }

    //通知白方行棋
    protected void noticeWhiteModify() {
        cur = 2;
        if (player_white != null) {
            player_white.sendMessage(Msger.youCanMove, "Ok");
        }
        if (player_black != null) {
            player_black.sendMessage(Msger.youNotMove, "Ok");
        }
        noticeAllRefreshGameInfo();
        noticeAllCountdown(-1, getCountdownSec());
    }

    @Override
    public void moveLater(Player player, int row, int col) {
        if (curGrids[row][col] != 0) {
            return; //默认只能落在空格
        }
        if (cur == 1) { //白棋落子
            if (player_black == player) {
                if (isModifying) { //白棋修改落子
                    blackPrePoint = null;
                    whitePrePoint = null;
                    doModifyRule(row, col, 1);
                }
                else { //白棋已经落下仅黑棋可落
                    blackPrePoint = new int[]{row, col, 1};
                    doSameTimeRule(blackPrePoint[0], blackPrePoint[1], blackPrePoint[2], whitePrePoint[0], whitePrePoint[1], whitePrePoint[2]);
                    stepAdd();;
                }
            }
        }
        else if (cur == 2) { //黑棋落子
            if (player_white == player) {
                if (isModifying) { //黑棋修改落子
                    blackPrePoint = null;
                    whitePrePoint = null;
                    doModifyRule(row, col, 2);
                }
                else {  //黑棋已经落下仅白棋可落
                    whitePrePoint = new int[]{row, col, 2};
                    doSameTimeRule(blackPrePoint[0], blackPrePoint[1], blackPrePoint[2], whitePrePoint[0], whitePrePoint[1], whitePrePoint[2]);
                    stepAdd();;
                }
            }
        }
        else if (cur == 3) { //双方都可以落下
            blackPrePoint = null;
            whitePrePoint = null;
            clearLineSignal();
            if (player_black == player) {
                blackPrePoint = new int[]{row, col, 1};
                noticeWhiteMove();
            }
            else if (player_white == player) {
                whitePrePoint = new int[]{row, col, 2};
                noticeBlackMove();
            }
        }
        else {

        }
    }

    @Override
    public void doSameTimeRule(int blackRow, int blackCol, int blackValue, int whiteRow, int whiteCol, int whiteValue) {
        // 双方落子位置相同
        if (blackRow == whiteRow && blackCol == whiteCol) {
            int lengthB = judgeFiveLengthPretend(blackRow, blackCol, 1);
            int lengthW = judgeFiveLengthPretend(whiteRow, whiteCol, 2);
            // 都能连五
            if (lengthB >= 5 && lengthW >= 5) {
                stepAdd();;
                curGrids[blackRow][blackCol] = 9; //直接变墙
                addHistory(); //添加历史记录
                isModifying = false;
                noticeAllMove();
            }
            // 黑方连五
            else if (lengthB >= 5) {
                //黑方可连五，白方优先占有
                needUpdated = new int[]{blackRow, whiteCol, 2};
                curGrids[blackRow][whiteCol] = 2;
                addHistory(); //添加历史记录（为了记录挤开事件）
                isModifying = true;
                noticeBlackModify();
            }
            // 白方连五
            else if (lengthW >= 5) {
                //白方可连五，黑方优先占有
                needUpdated = new int[]{blackRow, whiteCol, 1};
                curGrids[blackRow][whiteCol] = 1;
                addHistory(); //添加历史记录
                isModifying = true;
                noticeWhiteModify();
            }
            // 都没连五
            else {
                Random r = new Random(); //随机黑方白方占有
                if (r.nextBoolean()) {
                    needUpdated = new int[]{blackRow, blackCol, 2};
                    curGrids[blackRow][whiteCol] = 2;
                    addHistory(); //添加历史记录（为了记录挤开事件）
                    isModifying = true;
                    noticeBlackModify();
                }
                else {
                    needUpdated = new int[]{blackRow, blackCol, 1};
                    curGrids[blackRow][whiteCol] = 1;
                    addHistory(); //添加历史记录
                    isModifying = true;
                    noticeWhiteModify();
                }
            }
        }
        // 双方落子位置不同
        else {
            curGrids[blackRow][blackCol] = blackValue;
            curGrids[whiteRow][whiteCol] = whiteValue;
            int lengthB = judgeFiveLength(blackRow, blackCol, 1);
            int lengthW = judgeFiveLength(whiteRow, whiteCol, 2);
            if (lengthB >= 5 && lengthW >= 5) {
                //双方都成5互换落子位置，再判断一次
                curGrids[blackRow][blackCol] = whiteValue;
                curGrids[whiteRow][whiteCol] = blackValue;
                //再判断一次,仍然可以同时获胜则变为墙
                int lengthB2 = judgeFiveLength(blackRow, blackCol, 1);
                int lengthW2 = judgeFiveLength(whiteRow, whiteCol, 2);
                int lengthB3 = judgeFiveLength(blackRow, blackCol, 2);
                int lengthW3 = judgeFiveLength(whiteRow, whiteCol, 1);
                if ((lengthB2 >= 5 && lengthW2 >= 5) || (lengthB3 >= 5 && lengthW3 >= 5)) {
                    curGrids[blackRow][blackCol] = 9;
                    curGrids[whiteRow][whiteCol] = 9;
                }
                addTwoArrowSignal(blackRow, blackCol, whiteRow, whiteCol); //添加双线箭头
                stepAdd();;
                addHistory(); //添加历史记录
                isModifying = false;
                noticeAllMove();
            }
            else if (lengthB >= 5) {
                isModifying = false;
                doOver(WinMode.BLACK_WIN,player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
            }
            else if (lengthW >= 5) {
                isModifying = false;
                doOver(WinMode.WHITE_WIN,player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
            }
            else {
                stepAdd();;
                isModifying = false;
                noticeAllMove();
            }
        }
    }


    //结算地位等同于doSameTimeRule而不会回掉它
    public void doModifyRule(int row, int col, int value) {
        if (needUpdated != null) {
            addArrowSignal(needUpdated[0], needUpdated[1], row, col);
            curGrids[needUpdated[0]][needUpdated[1]] = needUpdated[2];
            needUpdated = null;
        }
        curGrids[row][col] = value;
        stepAdd();;
        addHistory(); //添加历史记录
        int length = judgeFiveLength(row, col, value);
        if (length >= 5) {
            isModifying = false;
            if (value == 1) {
                doOver(WinMode.BLACK_WIN,player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
            }
            else {
                doOver(WinMode.WHITE_WIN,player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
            }
        }
        else {
            isModifying = false;
            noticeAllMove();
        }
    }

    @Override
    public String getGameInfo() {
        List<Sign> selfSigns = new ArrayList<>(signList);
        addNeedUpdateSign(selfSigns);
        if (blackPrePoint != null && whitePrePoint != null) {
            selfSigns.add(new GroundSign(getIndex(blackPrePoint[0], blackPrePoint[1]), "#00000000", "#6600FF00", 1f, 0, 0));
            selfSigns.add(new GroundSign(getIndex(whitePrePoint[0], whitePrePoint[1]), "#00000000", "#6600FF00", 1f, 0, 0));
        }
        return "" + step +
                "&" + cur +
                "&" + blackScore +
                "&" + whiteScore +
                "&" + gameTip +
                "&" + GridsUtils.grids2Str(curGrids) +
                "&" + SignsUtils.signs2Str(selfSigns) +
                "&" + getCoordMode();
    }

    @Override
    protected String getBlackGameInfo() {
        int[][] selfGrids = GridsUtils.copyGrids(curGrids);
        List<Sign> selfSigns = new ArrayList<>(signList);
        addNeedUpdateSign(selfSigns);
        if (blackPrePoint != null && whitePrePoint != null) {
            selfSigns.add(new GroundSign(getIndex(blackPrePoint[0], blackPrePoint[1]), "#00000000", "#6600FF00", 1f, 0, 0));
            selfSigns.add(new GroundSign(getIndex(whitePrePoint[0], whitePrePoint[1]), "#00000000", "#6600FF00", 1f, 0, 0));
        }
        else if (blackPrePoint != null) {
            selfSigns.add(new GroundSign(getIndex(blackPrePoint[0], blackPrePoint[1]), "#00000000", "#6600FF00", 1f, 0, 1));
            selfGrids[blackPrePoint[0]][blackPrePoint[1]] = blackPrePoint[2];
        }
        return "" + step +
                "&" + cur +
                "&" + blackScore +
                "&" + whiteScore +
                "&" + gameTip +
                "&" + GridsUtils.grids2Str(selfGrids) +
                "&" + SignsUtils.signs2Str(selfSigns)+
                "&" + getCoordMode();
    }

    @Override
    protected String getWhiteGameInfo() {
        int[][] selfGrids = GridsUtils.copyGrids(curGrids);
        List<Sign> selfSigns = new ArrayList<>(signList);
        addNeedUpdateSign(selfSigns);
        if (blackPrePoint != null && whitePrePoint != null) {
            selfSigns.add(new GroundSign(getIndex(blackPrePoint[0], blackPrePoint[1]), "#00000000", "#6600FF00", 1f, 0, 0));
            selfSigns.add(new GroundSign(getIndex(whitePrePoint[0], whitePrePoint[1]), "#00000000", "#6600FF00", 1f, 0, 0));
        }
        else if (whitePrePoint != null) {
            selfSigns.add(new GroundSign(getIndex(whitePrePoint[0], whitePrePoint[1]), "#00000000", "#6600FF00", 1f, 0, 1));
            selfGrids[whitePrePoint[0]][whitePrePoint[1]] = whitePrePoint[2];
        }
        return "" + step +
                "&" + cur +
                "&" + blackScore +
                "&" + whiteScore +
                "&" + gameTip +
                "&" + GridsUtils.grids2Str(selfGrids) +
                "&" + SignsUtils.signs2Str(selfSigns)+
                "&" + getCoordMode();
    }

    private void addNeedUpdateSign(List<Sign> selfSigns) {
        if (needUpdated!=null){
            if (needUpdated[2] == 1) {
                selfSigns.add(new BadgeSign(getIndex(needUpdated[0], needUpdated[1]),"p",2, "#FFFFFFFF",ColorCost.DETAINED_BADGE_BLACK));
            }
            else if (needUpdated[2] == 2) {
                selfSigns.add(new BadgeSign(getIndex(needUpdated[0], needUpdated[1]), "p",2,"#FF000000",ColorCost.DETAINED_BADGE_WHITE));
            }
        }
    }


    public void addArrowSignal(int startRow, int startCol, int endRow, int endCol) {
        signList.add(new LineSign(getIndex(startRow, startCol), getIndex(endRow, endCol), ColorCost.MOVE_ARROW, 1));
    }


    public void addTwoArrowSignal(int startRow, int startCol, int endRow, int endCol) {
        signList.add(new LineSign(getIndex(startRow, startCol), getIndex(endRow, endCol), ColorCost.MOVE_ARROW, 2));
    }

    public void clearLineSignal() {
        signList.removeIf(sign -> sign instanceof LineSign);
    }


    //判断是否形成五连
    protected boolean judgeFive(int x, int y, int value) {
        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                if (dx == 0 && dy == 0) {
                    continue;
                }
                if (getJudgeLength(x, y, value, dx, dy) + getJudgeLength(x, y, value, -dx, -dy) - 1 >= 5) {
                    return true;
                }
            }
        }
        return false;
    }

    //返回五连的长度
    private int judgeFiveLength(int x, int y, int value) {
        int res = 0;
        int[][] dxdy = {{1, 0}, {-1, 1}, {0, 1}, {1, 1}};
        for (int i = 0; i < 4; i++) {
            int dx = dxdy[i][0];
            int dy = dxdy[i][1];
            int tmp = getJudgeLength(x, y, value, dx, dy) + getJudgeLength(x, y, value, -dx, -dy) - 1;
            if (tmp >= 5 && tmp > res) {
                res = tmp;
            }
        }
        return res;
    }

    protected int getJudgeLength(int x, int y, int value, int dx, int dy) {
        int length = 0;
        while (x >= 0 && y >= 0 && x < curGrids.length && y < curGrids.length) {
            if (curGrids[x][y] != value) {
                return length;
            }
            length++;
            x += dx;
            y += dy;
        }
        return length;
    }

    // 假设xy是value情况下，返回五连的长度
    private int judgeFiveLengthPretend(int x, int y, int value) {
        int originValue = curGrids[x][y];
        curGrids[x][y] = value;
        int res = 0;
        int[][] dxdy = {{1, 0}, {-1, 1}, {0, 1}, {1, 1}};
        for (int i = 0; i < 4; i++) {
            int dx = dxdy[i][0];
            int dy = dxdy[i][1];
            int tmp = getJudgeLength(x, y, value, dx, dy) + getJudgeLength(x, y, value, -dx, -dy) - 1;
            if (tmp >= 5 && tmp > res) {
                res = tmp;
            }
        }
        curGrids[x][y] = originValue;
        return res;
    }


}
